package com.chen10.cattle.service.impl;

import com.chen10.cattle.common.constants.EmailConstants;
import com.chen10.cattle.common.constants.FileConstants;
import com.chen10.cattle.common.constants.RedisKeyConstants;
import com.chen10.cattle.common.constants.UserConstants;
import com.chen10.cattle.common.enums.response.ErrorEnum;
import com.chen10.cattle.common.exception.BusinessException;
import com.chen10.cattle.common.utils.*;
import com.chen10.cattle.config.AppConfig;
import com.chen10.cattle.mapper.UserMapper;
import com.chen10.cattle.model.dto.ForgetPwdDTO;
import com.chen10.cattle.model.dto.UpdateUsernameDTO;
import com.chen10.cattle.model.dto.UserRankingPageDTO;
import com.chen10.cattle.model.page.Pager;
import com.chen10.cattle.model.vo.UserInfoVO;
import com.chen10.cattle.model.vo.UserRankingVO;
import com.chen10.cattle.model.vo.UserSearchVO;
import com.chen10.cattle.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private EmailUtil emailUtil;
    @Resource
    private AppConfig appConfig;
    @Resource
    private RedisUtil redisUtil;

    /**
     * 修改密码
     * @param forgetPwdDTO
     */
    @Override
    public void updatePassword(ForgetPwdDTO forgetPwdDTO) {
        //校验参数
        if(forgetPwdDTO == null){
            throw new BusinessException(ErrorEnum.PARAM_ERROR);
        }

        //邮箱校验参数
        if(!RegexUtils.isValidEmail(forgetPwdDTO.getEmail())) {
            throw new BusinessException(ErrorEnum.EMAIL_INVALID);
        }

        //判断邮箱是否存在
        if(userMapper.selectByEmail(forgetPwdDTO.getEmail())== null){
            throw new BusinessException(ErrorEnum.EMAIL_NOT_FOUND);
        }

        //校验密码合法
        if(!RegexUtils.isValidPassword(forgetPwdDTO.getNewPassword())) {
            throw new BusinessException(ErrorEnum.PASSWORD_INVALID);
        }

        //校验邮箱验证码
        String key = EmailConstants.FORGET_PASSWORD_CODE_KEY_PREFIX + forgetPwdDTO.getEmail();
        if(!emailUtil.verifyCode(key,forgetPwdDTO.getVerificationCode())){
            throw new BusinessException(ErrorEnum.EMAIL_CODE_ERROR);
        }

        //修改密码
        userMapper.updatePasswordByEmail(forgetPwdDTO.getEmail(), DigestUtils.md5DigestAsHex(forgetPwdDTO.getNewPassword().getBytes()));
    }

    @Override
    public List<UserSearchVO> getUsers(String param) {
        //校验参数
        if(StringUtils.isEmpty(param)){
            return null;
        }

        //判断是不是邮箱
        if(RegexUtils.isValidEmail(param)){
            List<UserSearchVO> list = new ArrayList<>();
            list.add(userMapper.searchByEmail(param));
            return list;
        }else{
            return userMapper.searchByUsername(param);
        }
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public UserInfoVO getUserInfo() {
        Integer userId = UserThreadLocal.getUserId();
        if(userId == null){
            throw new BusinessException(ErrorEnum.UNAUTHORIZED);
        }
        UserInfoVO userInfoVO = userMapper.getUserInfoById(UserThreadLocal.getUserId());

        //延长token时长
        String oldToken = (String) redisUtil.get(RedisKeyConstants.TOKEN_KEY_PREFIX+userId);
        String newToken = JwtUtil.refreshToken(oldToken);
        userInfoVO.setNewToken(newToken);

        //更新缓存
        redisUtil.setex(RedisKeyConstants.TOKEN_KEY_PREFIX+userId,newToken,JwtUtil.TOKEN_TIME_OUT_SECOND, TimeUnit.SECONDS);

        return userInfoVO;
    }


    /**
     * 修改用户名
     * @param updateUsernameDTO
     */
    @Override
    public void updateUsername(UpdateUsernameDTO updateUsernameDTO) {
        //校验参数
        if(updateUsernameDTO == null || updateUsernameDTO.getUserId()==null){
            throw new BusinessException(ErrorEnum.PARAM_ERROR);
        }
        Integer userId = updateUsernameDTO.getUserId();
        String newUsername = updateUsernameDTO.getUsername();

        if(StringUtils.isEmpty(newUsername)){
            throw new BusinessException(ErrorEnum.USERNAME_CANT_EMPTY);
        }

        //校验用户名合法
        if(!RegexUtils.isValidUsername(newUsername)) {
            throw new BusinessException(ErrorEnum.USERNAME_LENGTH_ERROR);
        }

        //修改用户名
        userMapper.updateUsername(updateUsernameDTO.getUserId(),newUsername);
    }


    /**
     * 更新头像
     * @param file
     * @return 新头像url
     */
    @Override
    public String updateAvatar(MultipartFile file) {
        //获取文件名
        String fileName = file.getOriginalFilename();
        if(fileName==null){
            throw new BusinessException(ErrorEnum.FILENAME_NULL);
        }
        //获取文件扩展名
        String fileSuffix = fileName.substring(fileName.indexOf("."));

        //校验文件类型
        if(!FileConstants.FILE_SUFFIX_PNG.equals(fileSuffix) && !FileConstants.FILE_SUFFIX_JPG.equals(fileSuffix)){
            throw new BusinessException(ErrorEnum.INVALID_IMAGE_FORMAT);
        }

        //新的文件名 （avatar_ + userId + 文件扩展名.jpg）
        String newFileName = FileConstants.AVATAR_FILE_NAME_PREFIX +UserThreadLocal.getUserId()+ FileConstants.FILE_SUFFIX_PNG;
        String path = appConfig.getAvatarDir();
        File fileDir = new File(path);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        File targetFile = new File(path, newFileName);
        try {
            file.transferTo(targetFile); //保存文件
        } catch (Exception e) {
            throw new BusinessException(ErrorEnum.FILE_UPLOAD_ERROR);
        }

        String newUrl = UserConstants.AVATAR_URL_PREFIX+"/"+newFileName;

        //更新数据库
        userMapper.updateAvatarByUserId(UserThreadLocal.getUserId(),newUrl);

        return newUrl;

    }

    /**
     * 排行榜分页查询
     * @return
     */
    @Override
    public Pager<UserRankingVO> getRankingPage(UserRankingPageDTO pageDTO) {
        //校验参数
        if (pageDTO == null) {
            throw new BusinessException(ErrorEnum.PARAM_ERROR);
        }
        int page = pageDTO.getPage();
        int size = pageDTO.getSize();

        if (page <= 0 || size <= 0) {
            throw new BusinessException(ErrorEnum.PARAM_ERROR);
        }

        int offset = (page - 1) * size;  // 计算分页的起始位置
        long total = userMapper.getCount(); // 查询总记录数

        // 获取分页数据
        List<UserRankingVO> rankingList = userMapper.getRankingPage(offset, size);

        Pager<UserRankingVO> pager = new Pager<>();
        pager.setPage(page);
        pager.setSize(size);
        pager.setTotal(total);
        pager.setData(rankingList);
        return pager;
    }
}
